#include "stdafx.h"
#include "AnImage.h"
#include <string>
#include <atlimage.h>


DWORD LAST_ERROR = 0;

static const DWORD SUCCESS = 0x00;
//error
static const DWORD ERROR_WIDTH = 0x0001;
static const DWORD ERROR_HEIGHT = 0x0002;
static const DWORD ERROR_CHANNEL = 0x0004;
static const DWORD ERROR_FORMAT  = 0x0008;
static const DWORD ERROR_PATH = 0x0010;
static const DWORD ERROR_LOAD = 0x0020;
static const DWORD ERROR_SAVE = 0x0040;
static const DWORD ERROR_EMPTYIMG = 0x0080;
static const DWORD ERROR_IMGPRTEQUAL = 0x0100;
static const DWORD ERROR_PARAMETER = 0x0200;

bool An::CreateImagebuffer(int width, int height, int channel, AnImageFormat format, AnImagebuffer ** buffer)
{
	if (width <= 0)
	{
		LAST_ERROR = ERROR_WIDTH;
		return false;
	}
	if (height <= 0)
	{
		LAST_ERROR = ERROR_HEIGHT;
		return false;
	}
	if (channel <= 0)
	{
		LAST_ERROR = ERROR_CHANNEL;
		return false;
	}
	if (format == AnImageFormat::UNKNOWN)
	{
		LAST_ERROR = ERROR_FORMAT;
		return false;
	}

	(*buffer) = new AnImagebuffer();
	(*buffer)->width = width;
	(*buffer)->height = height;
	(*buffer)->channel = channel;
	(*buffer)->isValid = false;
	(*buffer)->format = format;
	if ((*buffer)->format == AnImageFormat::PNG)
	{
		(*buffer)->channel = AN_CHANNEL_ALPHA;
	}
	(*buffer)->dataSize = width*height*channel;
	(*buffer)->buffer = new char[(*buffer)->dataSize];
	memset((*buffer)->buffer,NULL,sizeof(char)*(*buffer)->dataSize);
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::LoadImageBuffer(const char * path, AnImagebuffer ** buffer)
{
	if (!path)
	{
		LAST_ERROR = ERROR_PATH;
		return false;
	}
	/*LOAD*/
	CImage img;
//for unicode
#ifdef UNICODE
	int num = MultiByteToWideChar(0, 0, path, -1, NULL, 0);
	wchar_t *PATH = new wchar_t[num];
	MultiByteToWideChar(0, 0, path, -1, PATH, num);
	if (img.Load(PATH) != S_OK)
	{
		LAST_ERROR = ERROR_LOAD;
		delete[]PATH;
		(*buffer) = nullptr;
		return false;
	}
	delete[]PATH;
#else
	if (img.Load(path) != S_OK)
	{
		LAST_ERROR = ERROR_LOAD;
		(*buffer) = nullptr;
		return false;
	}
#endif // UNICODE

	if (img.IsNull())
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		(*buffer) = nullptr;
		return false;
	}
	/*INFO*/
	AnImageFormat imgFormat = getImageFormat(path);
	int width = img.GetWidth();
	int height = img.GetHeight();
	int channel = img.GetBPP()/8;
	if (channel == AN_CHANNEL_RGB)
	{
		if (imgFormat != AnImageFormat::BMP&&imgFormat != AnImageFormat::JPG)
		{
			LAST_ERROR = ERROR_FORMAT;
			(*buffer) = nullptr;
			return false;
		}
	}
	else if (channel == AN_CHANNEL_ALPHA)
	{
		if (imgFormat != AnImageFormat::PNG)
		{
			LAST_ERROR = ERROR_FORMAT;
			(*buffer) = nullptr;
			return false;
		}
	}
	/*create image*/
	if (!CreateImagebuffer(width, height, channel, imgFormat, buffer))
		return false;
	/*DATA*/
	BYTE* pDataSrc = (BYTE*)img.GetBits();
	int pitchSrc = img.GetPitch();
	if ((*buffer)->channel == AN_CHANNEL_SINGLE)
	{
		RGBQUAD ColorTab[256];
		for (int i = 0; i<256; i++)
		{
			ColorTab[i].rgbBlue = ColorTab[i].rgbGreen = ColorTab[i].rgbRed = i;
		}
		img.SetColorTable(0, 256, ColorTab);

		for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				//데繫돛붤펜匕
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_R + j*(*buffer)->channel + i*(*buffer)->width*(*buffer)->channel]=*(pDataSrc + pitchSrc*i + j*(*buffer)->channel + CImageColorArrange::CImageColor_B);
			}
		}
	}
	else
	{
		for (int i = 0; i<height; i++)
		{
			for (int j = 0; j<width; j++)
			{
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_R + j*channel + i*width*channel] = *(pDataSrc + pitchSrc*i + j*channel + CImageColorArrange::CImageColor_R);
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_G + j*channel + i*width*channel] = *(pDataSrc + pitchSrc*i + j*channel + CImageColorArrange::CImageColor_G);
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_B + j*channel + i*width*channel] = *(pDataSrc + pitchSrc*i + j*channel + CImageColorArrange::CImageColor_B);
				if (imgFormat == AnImageFormat::PNG)
				{
					(*buffer)->buffer[AnImgColorArrange::AnImgColor_A + j*channel + i*width*channel] = *(pDataSrc + pitchSrc*i + j*channel + CImageColorArrange::CImageColor_A);
				}
			}
		}
	}
	//
	(*buffer)->isValid = true;
	img.Destroy();
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::SaveImageBuffer(const char * path, AnImagebuffer * buffer)
{
	if (!path)
	{
		LAST_ERROR = ERROR_PATH;
		return false;
	}
	if (!buffer || !buffer->isValid)
	{
		LAST_ERROR=ERROR_EMPTYIMG;
		return false;
	}
	AnImageFormat imgFormat = getImageFormat(path);
	if (imgFormat == AnImageFormat::UNKNOWN)
	{
		LAST_ERROR = ERROR_FORMAT;
		return false;
	}
	/*make sure*/
	if (buffer->channel == AN_CHANNEL_RGB)
	{
		if (imgFormat != AnImageFormat::BMP&&imgFormat != AnImageFormat::JPG)
		{
			LAST_ERROR = ERROR_FORMAT;
			return false;
		}
	}
	else if (buffer->channel == AN_CHANNEL_ALPHA)
	{
		if (imgFormat != AnImageFormat::PNG)
		{
			LAST_ERROR = ERROR_FORMAT;
			return false;
		}
	}
	/*create*/
	CImage img;
	if (buffer->channel == AN_CHANNEL_ALPHA)
	{
		img.Create(buffer->width, buffer->height, buffer->channel * 8, CImage::createAlphaChannel);
	}
	else
	{
		img.Create(buffer->width, buffer->height, buffer->channel * 8);
	}
	if (img.IsNull())
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	}
		
	/*DATA*/
	BYTE* pDataSrc = (BYTE*)img.GetBits();
	int pitchSrc = img.GetPitch();

	if (buffer->channel == AN_CHANNEL_SINGLE)
	{
		//槨imgDst뭐芚256쌓뿍똑딧깊
		RGBQUAD ColorTab[256];
		for (int i = 0; i<256; i++)
		{
			ColorTab[i].rgbBlue = ColorTab[i].rgbGreen = ColorTab[i].rgbRed = i;
		}
		img.SetColorTable(0, 256, ColorTab);
		
		for (int i = 0; i < buffer->height; i++)
		{
			for (int j = 0; j < buffer->width; j++)
			{
				//데繫돛붤펜匕
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_B)= buffer->buffer[AnImgColorArrange::AnImgColor_R + j*buffer->channel + i*buffer->width*buffer->channel];
			}
		}
	}
	else
	{
		for (int i = 0; i<buffer->height; i++)
		{
			for (int j = 0; j<buffer->width; j++)
			{
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_R) = buffer->buffer[AnImgColorArrange::AnImgColor_R + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_G) = buffer->buffer[AnImgColorArrange::AnImgColor_G + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_B) = buffer->buffer[AnImgColorArrange::AnImgColor_B + j*buffer->channel + i*buffer->width*buffer->channel];
				if (buffer->channel == AN_CHANNEL_ALPHA)
				{
					*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_A) = buffer->buffer[AnImgColorArrange::AnImgColor_A + j*buffer->channel + i*buffer->width*buffer->channel];
				}
			}
		}
	}
	//for unicode
#ifdef UNICODE
	int num = MultiByteToWideChar(0, 0, path, -1, NULL, 0);
	wchar_t *PATH = new wchar_t[num];
	MultiByteToWideChar(0, 0, path, -1, PATH, num);
	if (img.Save(PATH) != S_OK)
	{
		LAST_ERROR = ERROR_SAVE;
		delete[]PATH;
		img.Destroy();
		return false;
	}
	delete[]PATH;
#else
	if (img.Save(path) != S_OK)
	{
		LAST_ERROR = ERROR_SAVE;
		img.Destroy();
		return false;
	}
#endif // UNICODE
	//Save
	img.Destroy();
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::CopyImageBuffer(AnImagebuffer **Dstbuffer, AnImagebuffer * Srcbuffer)
{
	if (!Srcbuffer || !Srcbuffer->isValid)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		*Dstbuffer = nullptr;
		return false;
	}
	if ((*Dstbuffer)&&(*Dstbuffer)->buffer)
	{
		ReleaseImgbuffer(Dstbuffer);
	}
	if (!CreateImagebuffer(Srcbuffer->width, Srcbuffer->height, Srcbuffer->channel, Srcbuffer->format, Dstbuffer))
	{
		*Dstbuffer = nullptr;
		return false;
	}
	memcpy((*Dstbuffer)->buffer, Srcbuffer->buffer,sizeof(char)*Srcbuffer->width*Srcbuffer->height*Srcbuffer->channel);
	(*Dstbuffer)->isValid = true;
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::GrayImgeBuffer(AnImagebuffer ** Dstbuffer, AnImagebuffer * Srcbuffer)
{
	if (!Srcbuffer || !Srcbuffer->isValid)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	}
		
	if (Srcbuffer->channel == AN_CHANNEL_SINGLE)
	{
		LAST_ERROR = ERROR_CHANNEL;
		return false;
	}

	if ((*Dstbuffer) == Srcbuffer)
	{
		LAST_ERROR = ERROR_IMGPRTEQUAL;
		return false;
	}
	if ((*Dstbuffer) && (*Dstbuffer)->buffer)
	{
		ReleaseImgbuffer(Dstbuffer);
	}
	if (!CreateImagebuffer(Srcbuffer->width, Srcbuffer->height, AN_CHANNEL_SINGLE, AnImageFormat::BMP, Dstbuffer))
	{
		*Dstbuffer = nullptr;
		return false;
	}
	for (int i = 0; i < (*Dstbuffer)->height; i++)
	{
		for (int j = 0; j < (*Dstbuffer)->width; j++)
		{
			
			uchar R = (Srcbuffer)->buffer[AnImgColorArrange::AnImgColor_R + j*Srcbuffer->channel + i*Srcbuffer->width*Srcbuffer->channel] & 0xFF;
			uchar G = (Srcbuffer)->buffer[AnImgColorArrange::AnImgColor_G + j*Srcbuffer->channel + i*Srcbuffer->width*Srcbuffer->channel] & 0xFF;
			uchar B = (Srcbuffer)->buffer[AnImgColorArrange::AnImgColor_B + j*Srcbuffer->channel + i*Srcbuffer->width*Srcbuffer->channel] & 0xFF;
			(*Dstbuffer)->buffer[AnImgColorArrange::AnImgColor_R + j*(*Dstbuffer)->channel + i*(*Dstbuffer)->width*(*Dstbuffer)->channel]=(R+G+B)/3;
		}
	}
	(*Dstbuffer)->isValid = true;
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::ThresholdImgeBuffer(AnImagebuffer ** buffer, int thresholdValueMin, int thresholdvalueMax)
{
	if (!buffer || !(*buffer) || !(*buffer)->isValid)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	}

	if ((*buffer)->channel != AN_CHANNEL_SINGLE)
	{
	     LAST_ERROR = ERROR_CHANNEL;
		 return false;
	}

	if (thresholdValueMin < 0 || thresholdValueMin>255)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}
		
	if (thresholdvalueMax < 0 || thresholdValueMin>255)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}
		
	if (thresholdValueMin > thresholdvalueMax)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}

    //threshold
	for (int i = 0; i < (*buffer)->height; i++)
	{
		for (int j = 0; j < (*buffer)->width; j++)
		{
			//데繫돛붤펜匕
			if (((*buffer)->buffer[AnImgColorArrange::AnImgColor_R + j*(*buffer)->channel + i*(*buffer)->width*(*buffer)->channel] & 0xFF) < thresholdValueMin)
			{
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_R + j*(*buffer)->channel + i*(*buffer)->width*(*buffer)->channel] = 0;
			}
			else
			{
				(*buffer)->buffer[AnImgColorArrange::AnImgColor_R + j*(*buffer)->channel + i*(*buffer)->width*(*buffer)->channel] = thresholdvalueMax;
			}
		}
	}
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::ShowImageBuffer(AnImagebuffer * buffer, CWnd *cWnd,bool autoAdapt)
{
	if (!buffer)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	} 

	if (!cWnd)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}

	CImage img;
	if (buffer->channel == AN_CHANNEL_SINGLE)
	{
		img.Create(buffer->width, buffer->height, buffer->channel * 8);
		//槨imgDst뭐芚256쌓뿍똑딧깊
		RGBQUAD ColorTab[256];
		for (int i = 0; i<256; i++)
		{
			ColorTab[i].rgbBlue = ColorTab[i].rgbGreen = ColorTab[i].rgbRed = i;
		}
		img.SetColorTable(0, 256, ColorTab);
		/*DATA*/
		BYTE* pDataSrc = (BYTE*)img.GetBits();
		int pitchSrc = img.GetPitch();
		for (int i = 0; i < buffer->height; i++)
		{
			for (int j = 0; j < buffer->width; j++)
			{
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_B) = buffer->buffer[AnImgColorArrange::AnImgColor_R + j*buffer->channel + i*buffer->width*buffer->channel];
			}
		}
	}
	else if (buffer->channel == AN_CHANNEL_RGB)
	{
		img.Create(buffer->width, buffer->height, buffer->channel * 8);
		/*DATA*/
		BYTE* pDataSrc = (BYTE*)img.GetBits();
		int pitchSrc = img.GetPitch();

		for (int i = 0; i<buffer->height; i++)
		{
			for (int j = 0; j<buffer->width; j++)
			{
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_R) = buffer->buffer[AnImgColorArrange::AnImgColor_R + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_G) = buffer->buffer[AnImgColorArrange::AnImgColor_G + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_B) = buffer->buffer[AnImgColorArrange::AnImgColor_B + j*buffer->channel + i*buffer->width*buffer->channel];
			}
		}
	}
	else if (buffer->channel == AN_CHANNEL_ALPHA)
	{
		img.Create(buffer->width, buffer->height, buffer->channel * 8, CImage::createAlphaChannel);

		/*DATA*/
		BYTE* pDataSrc = (BYTE*)img.GetBits();
		int pitchSrc = img.GetPitch();

		for (int i = 0; i<buffer->height; i++)
		{
			for (int j = 0; j<buffer->width; j++)
			{
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_R) = buffer->buffer[AnImgColorArrange::AnImgColor_R + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_G) = buffer->buffer[AnImgColorArrange::AnImgColor_G + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_B) = buffer->buffer[AnImgColorArrange::AnImgColor_B + j*buffer->channel + i*buffer->width*buffer->channel];
				*(pDataSrc + pitchSrc*i + j*buffer->channel + CImageColorArrange::CImageColor_A) = buffer->buffer[AnImgColorArrange::AnImgColor_A + j*buffer->channel + i*buffer->width*buffer->channel];
			}
		}
	}
	/*draw*/
    cWnd->Invalidate();
	CDC *pDc = cWnd->GetDC();
	HDC hdcCtrl= pDc->m_hDC;
	CRect rc;
	if (autoAdapt)
	{
		cWnd->GetWindowRect(&rc);
		cWnd->GetParent()->ScreenToClient(&rc);
		cWnd->MoveWindow(rc.left, rc.top, buffer->width, buffer->height, true);
	}
	cWnd->GetClientRect(&rc);
	img.Draw(hdcCtrl,rc);
	/*release*/
	img.Destroy();
    pDc->Detach();
	DeleteDC(hdcCtrl);
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::ReleaseImgbuffer(AnImagebuffer ** buffer)
{
	if (*buffer == nullptr)return false;
	delete [](*buffer)->buffer;
	(*buffer)->buffer = nullptr;
	(*buffer)->width = -1;
	(*buffer)->height = -1;
	(*buffer)->channel = -1;
	(*buffer)->dataSize = -1;
	(*buffer)->isValid = false;
	(*buffer)->format = AnImageFormat::UNKNOWN;
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::getImagebufferPixColor(int widthPos, int heightPos, AnImagebuffer * buffer, AnColor & color)
{
	if (!buffer || !buffer->isValid)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	}
	if (widthPos<0|| widthPos>buffer->width-1)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}
	if (heightPos<0 || heightPos>buffer->height - 1)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}

	color.R=buffer->buffer[AnImgColorArrange::AnImgColor_R + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] & 0xFF;
	color.G=buffer->buffer[AnImgColorArrange::AnImgColor_G + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] & 0xFF;
	color.B=buffer->buffer[AnImgColorArrange::AnImgColor_B + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] & 0xFF;
	if (buffer->channel== AN_CHANNEL_ALPHA)
	{
		color.A=buffer->buffer[AnImgColorArrange::AnImgColor_A + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] & 0xFF;
	}
	LAST_ERROR = SUCCESS;
	return true;
}

bool An::setImagebufferPixColor(int widthPos, int heightPos, AnImagebuffer * buffer, AnColor color)
{
	if (!buffer || !buffer->isValid)
	{
		LAST_ERROR = ERROR_EMPTYIMG;
		return false;
	}
	if (widthPos<0 || widthPos>buffer->width - 1)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}
	if (heightPos<0 || heightPos>buffer->height - 1)
	{
		LAST_ERROR = ERROR_PARAMETER;
		return false;
	}

	buffer->buffer[AnImgColorArrange::AnImgColor_R + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] = color.R;
	buffer->buffer[AnImgColorArrange::AnImgColor_G + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] = color.G;
	buffer->buffer[AnImgColorArrange::AnImgColor_B + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] = color.B;
	if (buffer->channel == AN_CHANNEL_ALPHA)
	{
		buffer->buffer[AnImgColorArrange::AnImgColor_A + widthPos*buffer->channel + heightPos*buffer->width*buffer->channel] = color.A;
	}
	LAST_ERROR = SUCCESS;
	return true;
}

AnImageFormat An::getImageFormat(const char * path)
{
	if (!path)
	{
		LAST_ERROR = ERROR_PATH;
		return AnImageFormat::UNKNOWN;
	}
	std::string pathstr = path;
	int pos=pathstr.rfind('.');
	if (pos <= 0)
	{
		LAST_ERROR = ERROR_PATH;
		return AnImageFormat::UNKNOWN;
	}
	std::string format = pathstr.substr(pos+1, pathstr.length()- pos);
	if (format=="bmp"|| format == "BMP")
	{
		LAST_ERROR = SUCCESS; 
		return AnImageFormat::BMP;
	}
	else if(format == "jpg" || format == "jpeg"|| format == "JPG" || format == "JPEG")
	{
		LAST_ERROR = SUCCESS;
		return AnImageFormat::JPG;
	}
	else if(format == "png" || format == "PNG")
	{
		LAST_ERROR = SUCCESS;
		return AnImageFormat::PNG;
	}
	LAST_ERROR = SUCCESS;
	return AnImageFormat::UNKNOWN;
}

DWORD getLastAnError()
{
	return LAST_ERROR;
}
